﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Reflection;
using System.Linq.Expressions;
using CoolCode.Linq.Expressions;

namespace CoolCode.Data.Linq
{
	public class Repository<T> : IRepository<T>, IQueryable<T>, IEnumerable<T>, IDisposable where T : class
	{
		private XDataContext db;

		internal Repository(XDataContext context)
		{
			this.db = context;
		}

		private Table<T> _table = null;

		protected virtual Table<T> table
		{
			get
			{
				if (_table == null)
					_table = db.GetTable<T>();
				return _table;
			}
		}

		#region IRepository<T> Members

		public virtual void Insert(T entity)
		{
			table.InsertOnSubmit(entity);
		}

		public virtual void Insert(IEnumerable<T> list)
		{
			table.InsertAllOnSubmit(list);
		}

		public virtual void Update(T entity)
		{
			table.Attach(entity, true);
		}

		public virtual void Update(T entity, T original)
		{
			table.Attach(entity, original);
		}

		public virtual void Update(IEnumerable<T> list)
		{
			table.AttachAll(list, true);
		}

		 
		/// <summary>
		/// 批量更新
		/// </summary>  
		/// <param name="predicate">查询条件表达式</param>
		/// <param name="updater">更新表达式</param>
		/// <returns>影响的行数</returns>
		public virtual int Update(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> updater)  
		{
			return table.Update2(predicate,updater);
		}
		 

		public virtual void Delete(T entity)
		{
			table.DeleteOnSubmit(entity);
		}

		public virtual void Delete(IQueryable<T> query)
		{
			table.DeleteAllOnSubmit(query);
		}

		public virtual void Delete(IEnumerable<T> list)
		{
			table.AttachAll(list);
			table.DeleteAllOnSubmit(list);
		}

		public virtual void Delete(Expression<Func<T, bool>> predicate)
		{
			var q = this.Where(predicate);
			table.DeleteAllOnSubmit(q);
		}

		public IQueryable<T> In<P>(Expression<Func<T, P>> property, IList<P> values)
		{
			//values.ThrowIfNullOrEmpty("value");

			//var parameter = property.GetParameters();
			//var constant = Expression.Constant(values);
			//Type type = typeof(P);
			//Expression nonNullProperty = property.Body;
			////如果是Nullable<X>类型，则转化成X类型
			//if (type.IsNullableType())
			//{
			//    type = type.GetNonNullableType();
			//    nonNullProperty = Expression.Convert(property.Body, type);
			//}
			//Expression<Func<P[], P, bool>> InExpression = (list, el) => list.Contains(el);
			//var methodExp = InExpression;
			//var invoke = Expression.Invoke(methodExp, constant, property.Body);
			//Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(invoke, parameter);

			values.ThrowIfNullOrEmpty("value");
			Expression<Func<T, bool>> lambda = ExpressionTreeHelpers.BuildContainsExpression(property, values);
			return table.Where(lambda);
		}

		public virtual IQueryable<T> Query()
		{
			return table;
		}

		public virtual IQueryable<T> Query(Expression<Func<T, bool>> predicate)
		{
			return table.Where(predicate);
		}

		//IQueryable<T> IRepository<T>.Where(Expression<Func<T, bool>> predicate)
		//{
		//    return table.Where(predicate);
		//}

		public List<T> List(IQueryable<T> query, bool withNoLock)
		{
			return db.ExecuteQuery<T>(query, withNoLock).ToList();
		}

		public virtual T Get(Expression<Func<T, bool>> predicate)
		{
			return this.table.FirstOrDefault(predicate);
		}

		public virtual ISingleResult<TResult> ExecuteStoredProcedure<TResult>(object instance, MethodInfo method, params object[] parameters)
		{
			IExecuteResult result = db.ExecuteStoredProcedure(instance, method, parameters);
			return ((ISingleResult<TResult>)result.ReturnValue);
		}

		public virtual IMultipleResults ExecuteStoredProcedure(object instance, MethodInfo method, params object[] parameters)
		{
			IExecuteResult result = db.ExecuteStoredProcedure(instance, method, parameters);
			return ((IMultipleResults)result.ReturnValue);
		}

		public virtual int Exec(string command, params object[] parameters)
		{
			return db.ExecuteCommand(command, parameters);
		}

		#endregion

		#region IEnumerable<T> Members

		public IEnumerator<T> GetEnumerator()
		{
			return this.table.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		#endregion

		#region IQueryable Members

		Type IQueryable.ElementType
		{
			get
			{
				return typeof(T);
			}
		}

		Expression IQueryable.Expression
		{
			get
			{
				return ((IQueryable)table).Expression; // return Expression.Constant(table);
			}
		}

		IQueryProvider IQueryable.Provider
		{
			get { return table; }
		}

		#endregion

		#region IDisposable Members

		public virtual void Dispose()
		{
			if (db != null)
			{
				db.Dispose();
			}
		}

		#endregion

		public override string ToString()
		{
			return table.ToString();
		}
	}


}
